package com.metagurukul.metagranth.model.common.connection;

import java.io.IOException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Properties;
import java.util.Vector;

import com.metagurukul.metagranth.model.common.dbutil.Util;


/**
 * 
 * ConnectionPoolFactory is a Singleton class.
 * 
 * Purpose of ConnectionPoolFactory class is make a pool of connections and when we
 * required connection object then we pickup a connection object from connection
 * pool vector and when use of connection object is complete then put the object
 * inside connection pool vector.
 * 
 * @author dheeraj kumar
 * 
 */

public class ConnectionPoolFactory {
	private Vector<Connection> pool = new Vector<Connection>();
	private String driverClass;
	private String url;
	private String username;
	private String password;
	private int poolSize;
	private static ConnectionPoolFactory instance;

	/**
	 * private constructor for Singleton class
	 */
	private ConnectionPoolFactory() {
		//read the data base properties.
		readDBProperties();
		init();
	}

	public static ConnectionPoolFactory getInstance() {
		if (instance == null) {
			instance = new ConnectionPoolFactory();
		}
		return instance;
	}

	/**
	 * readDBProperties() method is for reading the DataBase properties for db.properties File 
	 */
	private void readDBProperties() {
		try {
			
			Properties properties = new Properties();
			properties.load(getClass().getResourceAsStream("../dbresource/db.properties"));
			this.driverClass = properties.getProperty("driverClass");
			this.url = properties.getProperty("url");
			this.username = properties.getProperty("username");
			this.password = properties.getProperty("password");
			this.poolSize = Integer.parseInt(properties.getProperty("poolSize"));
		} catch (IOException ex) {
			ex.printStackTrace();
		} 
	}

	/**
	 * getConnection() method is for getting a connection object.
	 * 
	 * @return connection object
	 */
	private Connection getConnection() {
		Connection con = null;
		try {
			con = DriverManager.getConnection(url, username, password);
		} catch (SQLException ex) {
			ex.printStackTrace();
		}
		return con;
	}

	/**
	 * inti() method for make a pool of connection object
	 */
	private void init() {
		try {
			Class.forName(driverClass);
		} catch (ClassNotFoundException ex) {
			ex.printStackTrace();
		}
		Connection con = null;
		for (int i = 0; i < poolSize; i++) {
			con = getConnection();
			pool.add(con);
		}
	}

	/**
	 * getConnection() method is for get a connection object from connection
	 * pool.
	 * 
	 * @return connection object
	 */
	public Connection checkOut() {
		Connection con = null;
		if (pool.size() > 0) {
			con = (Connection) pool.remove(0);
		} else {
			con = getConnection();
		}
		return con;
	}

	/**
	 * checkIn() method is for put a connection object into pool
	 * 
	 */
	public void checkIn(Connection con) {
		if (con instanceof Connection) {
			if (pool.size() < poolSize) {
				pool.add(con);
			} else {
				Util.closeConnection(con);
			}
		} else {
			// throw exception
		}
	}

	/**
	 * release() method for release all the connection object from pool.
	 */
	public void release() {
		Connection con = null;
		for (int i = 0; i < poolSize;) {
			con = (Connection) pool.remove(0);
			Util.closeConnection(con);
		}
	}
	
	@Override
	protected void finalize() throws Throwable {
		super.finalize();
		if(instance!=null){
			instance=null;
		}
	}
}
